package com.freight.core.common.aop;


import com.freight.core.base.FreightBaseEntity;
import com.freight.core.common.annotation.SecretAnnotation;
import com.freight.core.common.utils.AESUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

@Slf4j
public class DecodeMethodParaResolver implements HandlerMethodArgumentResolver {


    /**
     * 如果参数上有自定义注解Base64DecodeStr的话就支持解析
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(SecretAnnotation.class)
                || parameter.hasMethodAnnotation(SecretAnnotation.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        /**
         * 因为这个注解是作用在方法和参数上的，所以要分情况
         */
        int count = parameter.hasMethodAnnotation(SecretAnnotation.class)
                ? parameter.getMethodAnnotation(SecretAnnotation.class).count()
                : parameter.getParameterAnnotation(SecretAnnotation.class).count();
        /**
         * 如果是实体类参数，就把前端传过来的参数构造成一个实体类
         * 在系统中本人把所有实体类都继承了BaseEntity
         */
        if (FreightBaseEntity.class.isAssignableFrom(parameter.getParameterType())) {
            Object obj = parameter.getParameterType().newInstance();
            webRequest.getParameterMap().forEach((k, v) -> {
                try {
                    BeanUtils.setProperty(obj, k, decodeStr(v[0], count));
                } catch (Exception e) {
                    log.error("参数解码有误", e);
                }
            });
            // 这里的return就会把转化过的参数赋给控制器的方法参数
            return obj;
            // 如果是非集合类，就直接解码返回
        } else if (!Iterable.class.isAssignableFrom(parameter.getParameterType())) {
            System.out.println(webRequest.getParameterNames().toString());
            String res = decodeStr(webRequest.getParameter(parameter.getParameterName()), count);
            return res;
        }
        return null;
    }

    /**
     * 解密参数
     *
     * @param str   Base64加密*次之后的密文
     * @param count *次
     * @return 明文
     */
    public static String decodeStr(String str, int count) {
        for (int i = 0; i < count; i++) {
            try {
                log.info("【解密前的数据 】" + str);
                str = AESUtil.encrypt(str);
                str = AESUtil.decrypt(str);
                log.info("【解密后的数据 】" + str);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return str;
    }
}